﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.SessionState;
using System.IO;
using SSOCommon;
using SSOClient.Config;

namespace SSOClient
{
    public partial class SSOClientCore : IHttpModule, IRequiresSessionState
    {

        public void Dispose()
        {

        }

        public string ServiceUrl
        {
            get
            {
                return SSOConfig.Instance.ServiceUrl;
            }
        }

        public void Init(HttpApplication context)
        {
            context.PreRequestHandlerExecute += new EventHandler((sender, arg) =>
            {
                if (HttpContext.Current.Handler is System.Web.UI.Page)
                {
                    Command cmd = Command.ParseCommand(HttpContext.Current.Request.QueryString);
                    SSOAction action = (SSOAction)Enum.Parse(typeof(SSOAction), cmd.Action);
                    if (action == SSOAction.Logout)
                    {
                        ClientLogout(HttpContext.Current);
                    }
                    if (!String.IsNullOrEmpty(StateManager.Token))
                    {
                        return;
                    }

                    if (String.IsNullOrEmpty(cmd.Sender) || String.IsNullOrEmpty(cmd.Action))
                    {
                        ClientLogin(HttpContext.Current);
                    }
                    if (Int32.Parse(cmd.Sender) == (int)SenderSource.Server)
                    {
                        switch (action)
                        {
                            case SSOAction.Login:
                                ServerLogin(HttpContext.Current);
                                break;
                        }
                    }
                    else if (Int32.Parse(cmd.Sender) == (int)SenderSource.Client)
                    {
                        switch (action)
                        {
                            case SSOAction.Login:
                                ClientLogin(HttpContext.Current);
                                break;

                            case SSOAction.Logout:
                                ClientLogout(HttpContext.Current);
                                break;

                            case SSOAction.Auth:
                                ClientAuth(HttpContext.Current);
                                break;
                        }

                    }
                    else
                    {
                        ClientLogin(HttpContext.Current);
                    }
                }
            });
        }

        private void ClientLogin(HttpContext context)
        {
            context.Response.Clear();
            context.Response.ContentType = "text/html";
            Dictionary<string, object> args = new Dictionary<string, object>();
            args.Add(ArgumentConstant.SITEID, SSOConfig.Instance.SiteID);
            args.Add(ArgumentConstant.SENDER, (int)SenderSource.Client);
            args.Add(ArgumentConstant.ACTION, (int)SSOAction.Login);
            args.Add(ArgumentConstant.REDIRECTURL, context.Request.Url.OriginalString);
            context.Response.StatusCode = 302;
            context.Response.RedirectLocation = Tools.GenerateUrl(SSOConfig.Instance.SingleLoginUrl, args);
            context.Response.End();
        }

        private void ClientLogout(HttpContext context)
        {
            Dictionary<string, object> queryArguments = new Dictionary<string, object>();
            queryArguments.Add(ArgumentConstant.SITEID, SSOConfig.Instance.SiteID);
            queryArguments.Add(ArgumentConstant.ACTION, (int)SSOAction.Logout);
            string token = GetParamValue(ArgumentConstant.TOKEN);
            if (token == String.Empty)
            {
                queryArguments.Add(ArgumentConstant.TOKEN, StateManager.Token);
            }
            else
            {
                queryArguments.Add(ArgumentConstant.TOKEN, token);
            }
            string requestUrl = Tools.GenerateUrl(ServiceUrl, queryArguments);
            //request sso server service
            Tools.SendRequest(requestUrl);
            //clear client session 
            StateManager.Token = null;
            StateManager.User = null;

            context.Response.StatusCode = 302;
            context.Response.RedirectLocation = SSOConfig.Instance.DefaultUrl;
            context.Response.End();
        }

        private void ClientAuth(HttpContext context)
        {
            string token = GetParamValue(ArgumentConstant.TOKEN);
            if (token == string.Empty)
            {
                ClientLogin(HttpContext.Current);
            }
            Dictionary<string, object> queryArguments = new Dictionary<string, object>();
            queryArguments.Add(ArgumentConstant.SITEID, SSOConfig.Instance.SiteID);
            queryArguments.Add(ArgumentConstant.ACTION, (int)SSOAction.Auth);
            queryArguments.Add(ArgumentConstant.TOKEN, token);
            string requestUrl = Tools.GenerateUrl(ServiceUrl, queryArguments);
            string responseData = Tools.SendRequest(requestUrl);
            bool validateSuccess;
            if (bool.TryParse(responseData, out validateSuccess))
            {
                if (!validateSuccess)
                {
                    ClientLogin(HttpContext.Current);
                }
                else
                {
                    StoreIdentityData(context, token);
                    return;
                }
            }
            ClientLogin(HttpContext.Current);
        }

        private void ServerLogin(HttpContext context)
        {
            string token = GetParamValue(ArgumentConstant.TOKEN);
            if (String.IsNullOrEmpty(token))
            {
                ClientLogin(context);
            }
            else
            {
                StoreIdentityData(context, token);
                context.Response.Clear();
                context.Response.ContentType = "text/html";
                string url = String.Format("{0}://{1}{2}", context.Request.Url.Scheme, context.Request.Url.Authority, context.Request.Url.AbsolutePath);
                context.Response.StatusCode = 302;
                context.Response.RedirectLocation = url;
                context.Response.End();
            }
        }

        private UserInfo GetUserInfo(HttpContext context)
        {
            string token = GetParamValue(ArgumentConstant.TOKEN);
            if (token == string.Empty)
            {
                ClientLogin(HttpContext.Current);
            }
            Dictionary<string, object> queryArguments = new Dictionary<string, object>();
            queryArguments.Add(ArgumentConstant.SITEID, SSOConfig.Instance.SiteID);
            queryArguments.Add(ArgumentConstant.ACTION, (int)SSOAction.GetUserInfo);
            queryArguments.Add(ArgumentConstant.TOKEN, token);
            string requestUrl = Tools.GenerateUrl(ServiceUrl, queryArguments);
            string responseData = Tools.SendRequest(requestUrl);
            UserInfo returnValue = null;
            MemoryStream responseDataStream = new MemoryStream();
            using (StreamWriter writer = new StreamWriter(responseDataStream))
            {
                writer.Write(responseData);
                writer.Flush();
                responseDataStream.Seek(0, SeekOrigin.Begin);
                returnValue = Tools.DeserializeData<UserInfo>(responseDataStream);
            }

            return returnValue;
        }

        private void StoreIdentityData(HttpContext context, string token)
        {
            StateManager.Token = token;
            if (StateManager.User == null)
            {
                StateManager.User = GetUserInfo(context);
            }
        }
    }
}
